package org.aspire.graphics.draw;

import java.awt.image.BufferedImage;

import org.aspire.core.sys.GameException;
import org.aspire.data.Emptyable;
import org.aspire.graphics.Color;
import org.aspire.graphics.DrawGraphics;
import org.aspire.graphics.Frame;
import org.aspire.graphics.frame.StandardFrame;
import org.aspire.graphics.frame.Texture;
import org.aspire.graphics.frame.TextureLoader;
import org.lwjgl.opengl.GL11;

/******************************************************************************
 * A draw graphics implementation for OpenGL rendering functions.
 * 
 * @author JPACarabuena
 *****************************************************************************/
public class OpenGLGraphics implements DrawGraphics, Emptyable {

	// ========================================================================
	// Constants
	// ========================================================================

	// ========================================================================
	// Static Methods
	// ========================================================================

	// ========================================================================
	// Fields
	// ========================================================================

	/**************************************************************************
	 * The color for this draw graphics.
	 *************************************************************************/
	private Color color;
	
	/**************************************************************************
	 * The texture loader for OpenGL image.
	 *************************************************************************/
	private TextureLoader loader;
	
	// ========================================================================
	// Constructors
	// ========================================================================

	/**************************************************************************
	 * Construct a new OpenGL graphics.
	 *************************************************************************/
	public OpenGLGraphics() {
		loader = new TextureLoader();
	}
	
	// ========================================================================
	// Getters & Setters
	// ========================================================================

	// ========================================================================
	// Override Methods
	// ========================================================================

	@Override
	public Color getColor() {
		return this.color;
	}
	
	@Override
	public void setColor(Color color) {
		this.color = color;
	}
	
	@Override
	public void drawLine(int x1, int y1, int x2, int y2) {
		GL11.glDisable(GL11.GL_TEXTURE_2D);

		this.setColor();
		
		GL11.glBegin(GL11.GL_LINES);
			GL11.glVertex2i(x1, y1);
			GL11.glVertex2i(x2, y2);
		GL11.glEnd();
		
		GL11.glEnable(GL11.GL_TEXTURE_2D);
	}

	@Override
	public void drawRect(int x, int y, int width, int height) {
		this.renderRectangle(x, y, width, height, GL11.GL_LINE_LOOP);
	}

	@Override
	public void fillRect(int x, int y, int width, int height) {
		this.renderRectangle(x, y, width, height, GL11.GL_QUADS);
	}

	@Override
	public void drawOval(int x, int y, int width, int height) {
		this.renderOval(x, y, width, height, GL11.GL_LINE_LOOP);
	}

	@Override
	public void fillOval(int x, int y, int width, int height) {
		this.renderOval(x, y, width, height, GL11.GL_TRIANGLE_FAN);
	}

	@Override
	public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
			throws GameException {

	}

	@Override
	public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
			throws GameException {

	}

	@Override
	public void drawString(String str, int x, int y) {

	}

	@Override
	public void drawImage(Frame image, int x, int y) {
		if(image instanceof StandardFrame) {
			GL11.glPushMatrix();
			
			Texture texture = this.loader.getTexture(
					(BufferedImage) image.getImage());
			texture.bind();
			
			GL11.glTranslatef(x, y, 0);
			
			GL11.glBegin(GL11.GL_QUADS);
				GL11.glTexCoord2f(0, 0);
				GL11.glVertex2f(0, 0);
	
				GL11.glTexCoord2f(0, texture.getHeight());
				GL11.glVertex2f(0, texture.getImageHeight());
	
				GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());
				GL11.glVertex2f(texture.getImageWidth(), texture.getImageHeight());
	
				GL11.glTexCoord2f(texture.getWidth(), 0);
				GL11.glVertex2f(texture.getImageWidth(), 0);
			GL11.glEnd();
			
			GL11.glPopMatrix();
		}
	}

	@Override
	public void clear() {
		// do nothing
	}

	@Override
	public boolean isEmpty() {
		return false;
	}
	
	// ========================================================================
	// Methods
	// ========================================================================

	private void setColor() {
		GL11.glColor4f(
				this.color.getRedComponent()/255f,
				this.color.getGreenComponent()/255f,
				this.color.getBlueComponent()/255f,
				this.color.getAlpha()/255f
				);
	}
	
	private void renderRectangle(int x, int y, int width, int height, int cap) {
		GL11.glDisable(GL11.GL_TEXTURE_2D);

		this.setColor();
		
		GL11.glBegin(cap);
			GL11.glVertex2i(x, y);
			GL11.glVertex2i(x+width, y);
			GL11.glVertex2i(x+width, y+height);
			GL11.glVertex2i(x, y+height);
		GL11.glEnd();
		
		GL11.glEnable(GL11.GL_TEXTURE_2D);
	}
	
	private void renderOval(int x, int y, int width, int height, int cap) {
		float theta;
		float angle_increment;
		float x1;
		float y1;
		
		angle_increment = (float) (2*Math.PI) / 90;
		GL11.glPushMatrix();
		
		GL11.glTranslatef(x+(width/2), y+(height/2), 0);

		this.setColor();
			
		GL11.glBegin(cap);
		for(theta = 0.0f; theta < (2*Math.PI); theta += angle_increment) {
			x1 = (float) (width/2 * Math.cos(theta));
			y1 = (float) (height/2 * Math.sin(theta));

			GL11.glVertex2f(x1, y1);
		}
		GL11.glEnd();
		
		GL11.glPopMatrix();
	}

	// ========================================================================
	// Inner & Anonymous Classes
	// ========================================================================
}